package org.mika.asm;

import java.util.HashMap;
import java.util.Map;

public class Opener {
	private Opener() {}
	
	private static Map<String, Class<?>> generatedClasses;
	private static Map<String, Object> generatedObjects;
	
	static {
		generatedClasses = new HashMap<String, Class<?>>();
		generatedObjects = new HashMap<String, Object>();
	}
	
	@SuppressWarnings("unchecked")
	public static <I> I openMethods(Object o, Class<I> iface) throws Exception {
		String name = o.getClass().getName() + "#" + iface.getName();
		synchronized (Opener.class) {
			if(!generatedClasses.containsKey(name)) {
				generatedClasses.put(name, PrivateMethodsFactory.createClass(o.getClass(), iface));
			}
		}
		return (I) generatedClasses.get(name).getConstructor(o.getClass()).newInstance(o);
	}
	
	@SuppressWarnings("unchecked")
	public static <I> I openFields(Object o, Class<I> gs) throws Exception {
		String name = o.getClass().getName() + "#" + gs.getName();
		synchronized (Opener.class) {
			if(!generatedClasses.containsKey(name)) {
				generatedClasses.put(name, PrivateFieldsFactory.createClass(o.getClass(), gs));
			}
		}
		return (I) generatedClasses.get(name).getConstructor(o.getClass()).newInstance(o);
	}	
	
	@SuppressWarnings("unchecked")
	public static <I> I openStaticMethods(Class c, Class<I> iface) throws Exception {
		String name = c.getName() + "#" + iface.getName();
		synchronized (Opener.class) {
			if(!generatedObjects.containsKey(name)) {
				generatedObjects.put(
					name, PrivateMethodsFactory.createStaticAccessor(c, iface)
				);
			}
		}
		return (I) generatedObjects.get(name);
	}
	
	@SuppressWarnings("unchecked")
	public static <I> I openStaticFields(Class c, Class<I> iface) throws Exception {
		String name = c.getName() + "#" + iface.getName();
		synchronized (Opener.class) {
			if(!generatedObjects.containsKey(name)) {
				generatedObjects.put(
					name, PrivateFieldsFactory.createStaticAccessor(c, iface)
				);
			}
		}
		return (I) generatedObjects.get(name);
	}
}
